<?php

/**
 * Created by PhpStorm.
 * User: wangan
 * Date: 2018/7/27
 * Time: 17:55
 */

/**
 * swoole_websocket_server 继承自 swoole_http_server
 * 设置了onRequest回调，websocket服务器也可以同时作为http服务器
 * 未设置onRequest回调，websocket服务器收到http请求后会返回http 400错误页面
 *
 * */
class http_websocket
{
    const HOST = '0.0.0.0';
    const PORT = 8814;

    public $http_websocket = null;
    public function __construct()
    {
        $this->http_websocket = new swoole_websocket_server(self::HOST, self::PORT);
        $this->http_websocket->set([
            'worker_num'=>4 ,//worker process num
            'document_root' => '../public',
            'enable_static_handler' => true,
            'task_worker_num'=>4
        ]);

        $this->http_websocket->on('start', [$this,'onStart']);
        $this->http_websocket->on('WorkerStart', [$this,'onWorkerStart']);
        $this->http_websocket->on('request', [$this,'onRequest']);
        $this->http_websocket->on('task', [$this,'onTask']);
        $this->http_websocket->on('finish', [$this,'onFinish']);
        $this->http_websocket->on('close', [$this,'onClose']);

        $this->http_websocket->on('open', [$this, 'onOpen']);
        $this->http_websocket->on('message', [$this, 'onMessage']);

        $this->http_websocket->start();

    }

    /**
     *
     * */
    public function onStart(swoole_server $server){
        //设置主进程名称
        swoole_set_process_name('live_master');
    }

    public function onWorkerStart(swoole_server $server, $worker_id){
        // 定义应用目录
        define('APP_PATH', __DIR__ . '/../application/');
        // 加载基础文件 ThinkPHP 引导文件
        //require __DIR__ . '/../thinkphp/base.php';
        require __DIR__ . '/../thinkphp/start.php';
    }

    /**
     * request 回调
    */
    public function onRequest($request, $response){
        $_SERVER = [];
        if($request->server){
            foreach ($request->server as $key => $val){
                $_SERVER[strtoupper($key)] = $val;
            }
        }

        if($request->header){
            foreach ($request->header as $key => $val){
                $_SERVER[strtoupper($key)] = $val;
            }
        }

        $_SERVER['argv'][1] = $_SERVER['PATH_INFO'];
        $_GET = [];
        if($request->get){
            foreach ($request->get as $key => $val){
                $_GET[$key] = $val;
            }
        }
        $_POST = [];
        if($request->post){
            foreach ($request->post as $key => $val){
                $_POST[$key] = $val;
            }
        }

        $_FILES = [];
        if($request->files){
            foreach ($request->files as $key => $val){
                $_FILES[$key] = $val;
            }
        }
        $this->writeLog();
        $_POST['swoole_ws_server'] = $this->http_websocket;
        ob_start();
        try{
            // 执行应用并响应
            think\Container::get('app')
                ->run()
                ->send();
        }catch (\Exception $exception){
            //todo
        }
        $res = ob_get_contents();
        ob_end_clean();
        $response->end($res);
    }

    /**
     * @param $data ['method']：方法  $data['data']：参数
    */
    public function onTask(swoole_server $serv, $task_id, $src_worker_id, $data){
        //todo
        try{
            $task = new app\commom\lib\Task();
            $method = $data['method'];
            $task->$method($data['data']);
        }catch (\Exception $exception){
            echo $exception->getMessage();
        }
        echo "worker:{$src_worker_id} task:$task_id finished";
    }

    public function onFinish(){
        //todo
    }

    /**
     * 当WebSocket客户端与服务器建立连接并完成握手后会回调此函数
    */
    public function onOpen (swoole_websocket_server $server, $request) {
        echo "server: handshake success with fd{$request->fd}\n";

        //记录所有在线用户的fd
        $fds_key = config('redis.SET_WEBSOCKET_CONNECTS');
        $res = \app\commom\lib\Predis::getInstance()->sadd($fds_key, $request->fd);

    }

    /**
     * 当服务器收到来自客户端的数据帧时会回调此函数。
    */
    public function onMessage(swoole_websocket_server $server, $frame){
        echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
        $server->push($frame->fd, "this is server");
    }

    public function onClose($ser, $fd){
        //todo
        //移除下线用户的fd
        $fds_key = config('redis.SET_WEBSOCKET_CONNECTS');
        $res = \app\commom\lib\Predis::getInstance()->srem($fds_key, $fd);
    }

    /**
     * 记录日志
    */
    public function writeLog(){
        $datas = array_merge(['date'=>date('Y-m-d H:i:s')], $_GET,$_POST,$_SERVER);
        $log = '';
        $log .= json_encode($datas). ' ';

        swoole_async_writefile(APP_PATH.'../runtime/log/'.date('Ym').'/'.date('d').'_access.log',$log.PHP_EOL,
            function (){

            }, FILE_APPEND);
    }
}

new http_websocket();